package com.ely.coupon.common.core.handler;

import cn.hutool.core.util.ReflectUtil;
import com.ely.coupon.common.core.ex.BaseException;
import com.ely.coupon.common.core.result.ResponseCode;
import com.ely.coupon.common.core.result.ResponseResult;
import com.ely.coupon.common.core.utils.ArgsError;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.List;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
public class GlobalHandlerException {


    @ExceptionHandler(BaseException.class)
    public ResponseResult<Object> handler(BaseException ex) {
        log.error(ex.getMessage());
        return ResponseResult.error(ex.getResponseCode());
    }

    /**
     * 未知异常处理
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResponseResult<Object> handler(Exception ex) {
        log.error(ex.getMessage());
        return ResponseResult.error();
    }

    /**
     * 404 错误
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseResult<Object> handlerNoFoundException(Exception e) {
        log.error(e.getMessage(), e);
        return ResponseResult.error(ResponseCode.SYS_ERROR);
    }


    /**
     * 实体参数类错误的异常处理
     *
     * @param exception
     * @return
     * @throws Exception
     */
    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseResult<Object> methodArgumentNotValidHandler(MethodArgumentNotValidException exception) {
        //按需重新封装需要返回的错误信息
        List<String> errors = exception.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        return ResponseResult.error(ResponseCode.PARAM_TYPE_ERROR, errors);
    }

    /**
     * ConstraintViolationException
     * 单个参数违反约束校验异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseResult<List<ArgsError>> handleConstraintViolationException(ConstraintViolationException e) {
        return ResponseResult.error(ResponseCode.PARAMS_IS_INVALID, e.getConstraintViolations().stream().map(constraintViolation -> {
            List<Path.Node> nodeList = (List<Path.Node>) ReflectUtil.getFieldValue(constraintViolation.getPropertyPath(), "nodeList");
            return ArgsError.builder().fieldName(nodeList.get(nodeList.size() - 1).getName()).build();
        }).collect(Collectors.toList()));
    }

}
